<?php
/**
 * Created by PhpStorm.
 * User: jjj
 * Date: 2017/8/31
 * Time: 17:03
 */

namespace app\callback\controller;


use app\common\lib\aop\AopClient;
use app\common\lib\pay\WeixinPay;
use app\common\lib\pay\WxPayCallback;
use app\common\model\BuyBill;
use phpseclib\Crypt\RSA;
use phpseclib\File\X509;
use think\Log;
use think\Validate;


class Pay
{
    /**
     * 处理post表单验证，
     * @param $validateRules array
     * @param $params null|array
     * @return mixed
     * @throws \Exception
     */
    private function getAndCheckForm($validateRules, $params = null) {
        $form = $params ? $params : input('post.');
        $validate = new Validate($validateRules);
        if(!$validate->check($form)) {
            throw new \Exception($validate->getError());
        }
        return $form;
    }

    /**
     * 直接返回退出，支付宝要求返回字符串，不是json或html
     *
     * @param $re
     */
    private function return_direct($re) {
        header('Content-Type: text/plain');
        echo $re;
        die;
    }

    /**
     * Actions
     */
    /**
     * 微信支付回调
     */
    public function weixin() {
        header('Content-Type: text/xml');

        $notify = new WxPayCallback();
        $notify->Handle(false);

        die;
/*
        $wxp = WeixinPay::getInstance();

        $form = null;
        try{
            $post = file_get_contents('php://input');
            if (empty($post)) $wxp->printXml([
                'return_code' => 'FAIL',
                'return_msg' => ''
            ]);
            $form = $wxp->parseXml($post);

            $form = $this->getAndCheckForm([
                ['notify_time', 'require',],
                ['notify_type', 'require',],
                ['notify_id', 'require',],
                ['app_id', 'require',],
                ['charset', 'require',],
                ['version', 'require',],
                ['sign_type', 'require',],
                ['sign', 'require',],
                ['transaction_id', 'require',],
                ['out_trade_no', 'require',],
            ], $form);

        }catch (\Exception $ex){
            Log::error($ex);
            $wxp->printXml([
                'return_code' => WeixinPay::CODE_FAIL,
                'return_msg' => $ex->getMessage(),
            ]);
        }

        $bill = BuyBill::get(['bill_no' => $form['out_trade_no']]);
        // 订单不存在
        if (empty($bill)) {
            $wxp->printXml([
                'return_code' => WeixinPay::CODE_FAIL,
                'return_msg' => '订单不存在',
            ]);
        }

        // 金额不正确
        if (round($form['total_amount'],2) != round($bill->bill_pay_amount,2)) {
            $wxp->printXml([
                'return_code' => WeixinPay::CODE_FAIL,
                'return_msg' => '金额不正确',
            ]);
        }

        // 订单已经完成，已支付
        if ($bill->bill_have_paid) {
            $wxp->printXml([
                'return_code' => WeixinPay::CODE_SUCCESS,
                'return_msg' => '订单已完成',
            ]);
        }

        $bill->bill_paytime = strtotime($form['notify_time']);
        $bill->pay_trade_no = $form['trade_no'];

        $re = $bill->successPay();
        if ($re) {
            $wxp->printXml([
                'return_code' => WeixinPay::CODE_SUCCESS,
                'return_msg' => '操作成功',
            ]);
        } else {
            $wxp->printXml([
                'return_code' => 'FAIL',
                'return_msg' => '操作失败',
            ]);
        }
*/
    }

    const ALIPAY_FAILED = 'fail';
    const ALIPAY_SUCCESS = 'success';
    /**
     * 支付宝回调
     */
    public function alipay() {

        $form = null;
        try{
            $form = $this->getAndCheckForm([
                ['notify_time', 'require',],
                ['notify_type', 'require',],
                ['notify_id', 'require',],
                ['app_id', 'require',],
                ['charset', 'require',],
                ['version', 'require',],
                ['sign_type', 'require',],
                ['sign', 'require',],
                ['trade_no', 'require',],
                ['out_trade_no', 'require',],
                ['trade_status', 'require',],
                ['total_amount', 'require',],
            ]);
        }catch (\Exception $ex){
            Log::error($ex);
            $this->return_direct(self::ALIPAY_FAILED);
        }

        if ('trade_status_sync' != $form['notify_type']) {
            $this->return_direct(self::ALIPAY_FAILED);
        }

        // 签名不正确
        $aop = AopClient::getInstance();
        if (!$aop->rsaCheck($form)) {
            $this->return_direct(self::ALIPAY_FAILED);
        }

        // 参数appId不正确，或状态未结束
        if ($form['app_id'] != $aop->appId ||
            !('TRADE_SUCCESS' == $form['trade_status'] || 'TRADE_FINISHED' == $form['trade_status'])
        ) {
            $this->return_direct(self::ALIPAY_FAILED);
        }

        $bill = BuyBill::get(['bill_no' => $form['out_trade_no']]);
        // 订单不存在
        if (empty($bill)) {
            $this->return_direct(self::ALIPAY_FAILED);
        }

        // 金额不正确
        if (round($form['total_amount'],2) != round($bill->bill_pay_amount,2)) {
            $this->return_direct(self::ALIPAY_FAILED);
        }

        // 订单已经完成，已支付，返回成功
        if ($bill->bill_have_paid) {
            $this->return_direct(self::ALIPAY_SUCCESS);
        }

        // 重复的订单
        if ($bill->chkBought()) {
            // todo 处理重复订单的支付
            Log::error($bill->bill_id.'有重复的购买');
            $this->return_direct(self::ALIPAY_FAILED);
        }

        $bill->bill_paytime = strtotime($form['notify_time']);
        $bill->pay_trade_no = $form['trade_no'];
        $re = $bill->successPay();
        if ($re) $this->return_direct(self::ALIPAY_SUCCESS);
        else $this->return_direct(self::ALIPAY_FAILED);
    }


    /**
     * allinpay
     * 通联支付回调处理
     *
     * @author zhengkai
     * @date 2018-01-09
     *
     * @throws \think\exception\DbException
     */
    public function allinpay()
    {
        $form = input('post.');

        $resArr = [
            'merchantId' => $form['merchantId'], // 商户号
            'version' => $form['version'], // 支付网关接口版本
            'language' => $form['language'], // 页面语言
            'signType' => $form['signType'], // 签名类型
            'payType' => $form['payType'], // 支付方式
            'issuerId' => $form['issuerId'], // 发卡方机构代码
            'paymentOrderId' => $form['paymentOrderId'], // 通联订单号
            'orderNo' => $form['orderNo'], // 商户订单号
            'orderDatetime' => $form['orderDatetime'], // 商户订单提交时间
            'orderAmount' => $form['orderAmount'], // 商户订单金额，单位：分
            'payDatetime' => $form['payDatetime'], // 订单支付完成时间
            'payAmount' => $form['payAmount'], // 订单实际支付金额
            'ext1' => $form['ext1'], // 扩展字段
            'ext2' => $form['ext2'], // 扩展字段
            'payResult' => $form['payResult'], // 支付结果 1=成功
            'errorCode' => $form['errorCode'], // 错误代码
            'returnDatetime' => $form['returnDatetime'], // 支付结果返回时间
            'signMsg' => $form['signMsg'] // 签名字符串
        ];

        $bill = BuyBill::get(['bill_no' => $form['orderNo']]);

        if (empty($bill)) {
            Log::error('通联支付错误信息：订单不存在');
            exit;
        }

        if (((int)$form['payAmount']/100) != $bill->bill_pay_amount) {
            Log::error('通联支付错误信息：订单付款金额不正确');
            exit;
        }

        if ($bill->bill_have_paid) {
            Log::error('通联支付错误信息：订单已付款');
            exit;
        }

        if ($bill->chkBought()) {
            Log::error("通联支付错误信息：{$bill->bill_id}有重复的购买");
            exit;
        }

        // 支付完成时间处理
        $payDatetime = $form['payDatetime'];
        $payTime = substr($payDatetime, 0, 4);
        $payTime .= '-'.substr($payDatetime, 4, -8);
        $payTime .= '-'.substr($payDatetime, 6, -6);
        $payTime .= ' '.substr($payDatetime, 8, -4);
        $payTime .= ':'.substr($payDatetime, 10, -2);
        $payTime .= ':'.substr($payDatetime, 12, 14);

        // 签名字符串拼接
        $signStr = '';
        foreach ($resArr as $key=>$val) {
            if ($val!=="" && $key!=='signMsg') $signStr .= $key.'='.$val.'&';
        }
        $signStr = rtrim($signStr, '&');

        $certFile = file_get_contents(ROOT_PATH.'TLCert-test.cer');
        $x509 = new X509();
        $rsa = new RSA();

        // 根据签名类型选择验签方式，并返回支付结果
        switch ($resArr['signType']) {
            case 1:
                $x509->loadX509($certFile);
                $pubKey = $x509->getPublicKey();

                $rsa->loadKey($pubKey);
                $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);

                $verifySign =  $rsa->verify($signStr, base64_decode(trim($resArr['signMsg'])));
                if ($verifySign) {
                    if ($resArr['payResult']==1) {
                        $bill->pay_trade_no = $form['paymentOrderId'];
                        $bill->bill_pay_amount = (int)$form['payAmount']/100;
                        $bill->bill_paytime = strtotime($payTime);
                        $bill->bill_have_paid = true;
                    } else {
                        $bill->pay_trade_no = $form['paymentOrderId'];
                        $bill->bill_pay_amount = (int)$form['payAmount']/100;
                        $bill->bill_paytime = strtotime($payTime);
                        $bill->bill_have_paid = false;

                        Log::error('通联支付错误信息：支付失败');
                    }
                } else {
                    $bill->pay_trade_no = $form['paymentOrderId'];
                    $bill->bill_pay_amount = (int)$form['payAmount']/100;
                    $bill->bill_paytime = strtotime($payTime);
                    $bill->bill_have_paid = false;

                    Log::error('通联支付错误信息：验签失败，支付失败');
                }

                break;
            default : // signType=0
                if($resArr['signMsg'] == strtoupper(md5($signStr."&key=".config('allinpay.md5Key')))) {
                    if ($resArr['payResult']==1) {
                        $bill->pay_trade_no = $form['paymentOrderId'];
                        $bill->bill_pay_amount = (int)$form['payAmount']/100;
                        $bill->bill_paytime = strtotime($payTime);
                        $bill->bill_have_paid = true;
                    } else {
                        $bill->pay_trade_no = $form['paymentOrderId'];
                        $bill->bill_pay_amount = (int)$form['payAmount']/100;
                        $bill->bill_paytime = strtotime($payTime);
                        $bill->bill_have_paid = false;

                        Log::error('通联支付错误信息：支付失败');
                    }
                } else {
                    $bill->pay_trade_no = $form['paymentOrderId'];
                    $bill->bill_pay_amount = (int)$form['payAmount']/100;
                    $bill->bill_paytime = strtotime($payTime);
                    $bill->bill_have_paid = false;

                    Log::error('通联支付错误信息：验签失败，支付失败');
                }
                break;
        }

        $bill->successPay();
    }
}